package com.liao.badminton.service.impl;

import java.util.*;
import java.util.stream.Collectors;

import cn.hutool.core.util.IdUtil;
import cn.hutool.core.util.ObjectUtil;
import com.liao.badminton.code.*;
import com.github.pagehelper.PageHelper;
import com.github.pagehelper.PageInfo;
import com.liao.badminton.code.myenum.GroupAdminEnum;
import com.liao.badminton.context.BaseContextHandler;
import com.liao.badminton.dto.UserGroupRefDto;
import com.liao.badminton.entity.SystemUsers;
import com.liao.badminton.mapper.JoinGroupApplyMapper;
import com.liao.badminton.redis.RedisEnum;
import com.liao.badminton.redis.RedisUtil;
import com.liao.badminton.code.util.EntityUtils;
import com.liao.badminton.code.util.CheckUtil;
import com.baomidou.mybatisplus.core.conditions.query.LambdaQueryWrapper;
import com.liao.badminton.entity.BadmintonGroup;
import com.liao.badminton.dto.BadmintonGroupDto;
import com.liao.badminton.service.BadmintonGroupService;
import com.liao.badminton.service.SystemUsersService;
import com.liao.badminton.service.UserGroupRefService;
import com.liao.badminton.vo.BadmintonGroupVo;
import com.liao.badminton.mapper.BadmintonGroupMapper;
import org.springframework.transaction.annotation.Propagation;
import org.springframework.transaction.annotation.Transactional;
import org.springframework.stereotype.Component;
import lombok.extern.log4j.Log4j2;
import com.baomidou.mybatisplus.extension.service.impl.ServiceImpl;

import javax.annotation.Resource;

import static cn.hutool.core.util.ObjectUtil.isEmpty;
import static cn.hutool.core.util.ObjectUtil.isNotEmpty;

/**
 * @author liaocheng
 * @date 2024-10-31
 * description:群表
 */
@Component
@Log4j2
public class BadmintonGroupServiceImpl extends ServiceImpl<BadmintonGroupMapper, BadmintonGroup> implements BadmintonGroupService {

    @Resource
    SystemUsersService systemUsersService;
    @Resource
    UserGroupRefService userGroupRefService;

    @Resource
    private JoinGroupApplyMapper joinGroupApplyMapper;

    /**
     * 新增
     */
    @Override
    @Transactional(propagation = Propagation.REQUIRED, timeout = 10, rollbackFor = Exception.class)
    public Long saveBadmintonGroup(BadmintonGroupDto param) throws ProjectException {
        BadmintonGroup badmintonGroup = param.invertEntity();
        badmintonGroup.setGroupCode(generateGroupCode());
        EntityUtils.setCreatAndUpdateInfo(badmintonGroup);
        this.save(badmintonGroup);

        //群id和名字唯一
        Long currUserID = BaseContextHandler.getCurrUserID();
        if (isNotEmpty(currUserID)) {
            SystemUsers byId = systemUsersService.getById(currUserID);
            UserGroupRefDto saveUserGroupRef = new UserGroupRefDto();
            saveUserGroupRef.setGroupId(badmintonGroup.getId());
            saveUserGroupRef.setUserName(param.getUserGroupName() == null ? byId.getNickname() == null ? byId.getUsername() : byId.getNickname() : param.getUserGroupName());
            saveUserGroupRef.setUserId(currUserID);
            saveUserGroupRef.setLoginDefault(1);
            saveUserGroupRef.setAdminType(GroupAdminEnum.owner.getCode());
            userGroupRefService.saveUserGroupRef(saveUserGroupRef);
        }
        return badmintonGroup.getId();
    }

    private String generateGroupCode() {
        String groupCode = IdUtil.nanoId(8);
        while (this.findBadmintonGroupByCode(groupCode) != null) {
            groupCode = IdUtil.nanoId(8);
        }
        return groupCode;
    }

    /**
     * 删除
     */
    @Override
    @Transactional(propagation = Propagation.REQUIRED, timeout = 10, rollbackFor = Exception.class)
    public ResponseRest<Boolean> deletesBadmintonGroup(BadmintonGroupDto param) throws ProjectException {
        boolean bool = this.removeByIds(param.getDelIds());
        if (bool) {
            param.getDelIds().forEach(id -> RedisUtil.toDelete(RedisEnum.CACHE_TABLE_DATA, "badmintonGroup", "id", id));
        }
        return ResponseRest.suc("deletesBadmintonGroup", true);
    }

    @Override
    public BadmintonGroup findBadmintonGroupByCode(String groupCode) {
        return this.baseMapper.selectOne(new LambdaQueryWrapper<BadmintonGroup>().eq(BadmintonGroup::getGroupCode, groupCode));
    }

    /**
     * 修改
     */
    @Override
    @Transactional(propagation = Propagation.REQUIRED, timeout = 10, rollbackFor = Exception.class)
    public ResponseRest<Boolean> updateBadmintonGroup(BadmintonGroupDto param) throws ProjectException {
        BadmintonGroup badmintonGroup = param.invertEntity();
        EntityUtils.setUpdatedInfo(badmintonGroup);
        boolean bool = this.updateById(badmintonGroup);
        if (bool) {
            RedisUtil.toDelete(RedisEnum.CACHE_TABLE_DATA, "badmintonGroup", "id", param.getId());
        }
        return ResponseRest.suc("updateBadmintonGroup", true);
    }

    /**
     * 查询列表
     */
    @Override
    public ResponseRest<PageInfo<BadmintonGroupVo>> findBadmintonGroupByPageParam(PageParam<BadmintonGroupDto> pageParam) throws ProjectException {
        CheckUtil.checkValue(pageParam, "pageParam");
        ResponseRest resp = ResponseRest.suc("findBadmintonGroupByPageParam");
        PageHelper.startPage(pageParam.getCurrent(), pageParam.getSize());
        LambdaQueryWrapper<BadmintonGroup> query = new LambdaQueryWrapper<>();
        List<BadmintonGroup> list = this.list(query);
        List<BadmintonGroupVo> collect = list.stream().parallel().map(entity -> BadmintonGroupVo.invertToVo(entity)).collect(Collectors.toList());
        resp.setData(new PageInfo<>(collect));
        return resp;
    }

    /**
     * 查询详情
     */
    @Override
    public ResponseRest<BadmintonGroupVo> findDetail(BadmintonGroupDto param) throws ProjectException {
        Object getDate = RedisUtil.toGetDate(RedisEnum.CACHE_TABLE_DATA, "badmintonGroup", "id", param.getId());
        if (isNotEmpty(getDate)) {
            RedisUtil.toFlushExpire(RedisEnum.CACHE_TABLE_DATA, "badmintonGroup", "id", param.getId());
            return ResponseRest.suc("findDetail", (BadmintonGroupVo) getDate);
        }
        BadmintonGroupVo vo = null;
        BadmintonGroup db = this.getById(param.getId());
        if (isNotEmpty(db)) {
            vo = BadmintonGroupVo.invertToVo(db);
            RedisUtil.toSaveRedis(RedisEnum.CACHE_TABLE_DATA, "badmintonGroup", "id", param.getId(), vo, null);
        }
        return ResponseRest.suc("findDetail", vo);
    }

    @Override
    public void updateCompetitionNum(Long groupId, Integer num) {
        baseMapper.updateCompetitionNum(groupId, num);
    }

    @Override
    public void updateActiveNum(Long groupId, Integer num) {
        baseMapper.updateActiveNum(groupId, num);
    }

    @Override
    public ResponseRest getListByUserId(PageParam<BadmintonGroupDto> pageParam) {
        CheckUtil.checkValue(pageParam, "pageParam");
        if (ObjectUtil.isEmpty(pageParam.getArgs())) {
            BadmintonGroupDto badmintonGroupDto = new BadmintonGroupDto();
            badmintonGroupDto.setUserId(BaseContextHandler.getCurrUserID());
            pageParam.setArgs(badmintonGroupDto);
        }

        ResponseRest resp = ResponseRest.suc("getListByUserId");
        PageHelper.startPage(pageParam.getCurrent(), pageParam.getSize());
        List<BadmintonGroupVo> list = baseMapper.getListByUserId(pageParam);
        List<Long> collect = list.stream().map(BadmintonGroupVo::getId).collect(Collectors.toList());
        if (isNotEmpty(collect)) {
            Map<Long, Map<String, Integer>> gjMap = joinGroupApplyMapper.findGroupJoinNum(collect);
            if (isNotEmpty(gjMap)) {
                list.forEach(vo -> {
                    if (gjMap.containsKey(vo.getId())) {
                        vo.setJoinNum(Integer.parseInt(gjMap.get(vo.getId()).get("num") + ""));
                    }
                });
            }
        }
        resp.setData(new PageInfo<>(list));
        return resp;
    }

    @Override
    public List<BadmintonGroupVo> findGroupByUserId(Long userId) {
        if (isEmpty(userId)) {
            userId = BaseContextHandler.getCurrUserID();
        }
        List<BadmintonGroupVo> list = baseMapper.findGroupByUserId(userId);
        return list;
    }

}
